#pragma once

#include <glm/glm.hpp>
#include "SourceCode/Renderer/Shader.h"

namespace Hazal
{
	typedef unsigned int GLenum;

	static GLenum ShaderTypeFromString(const std::string& strType);

	class COpenGLShader : public CShader
	{
	public:
		COpenGLShader(const std::string& strShaderName, const std::string& strVertexSrc, const std::string& strFragmentSrc);

		COpenGLShader(const std::string& strShaderPath);

		~COpenGLShader();

	public:
		void Bind() const override;

		void Unbind() const override;

		const std::string& GetName() const override;

		void SetMat4(const std::string& strUniform, const glm::mat4& mat4) override;

		void SetFloat4(const std::string& strUniform, const glm::vec4& vec4) override;

		void SetFloat3(const std::string& strUniform, const glm::vec3& vec3) override;

		void SetFloat(const std::string& strUniform, float fValue) override;

		void SetInt(const std::string& strUniform, int nVal) override;

		void SetIntArray(const std::string& strUniform, const int* nVals, uint32_t unArySize) override;

	private:
		void UploadUniformMat4(const std::string& strUniform, const glm::mat4& matrix);

		void UploadUniformFloat4(const std::string& strUniform, const glm::vec4& vec);

		void UploadUniformFloat3(const std::string& strUniform, const glm::vec3& vec);

		void UploadUniformInt(const std::string& strUniform, const int nSlot);

		void UploadUniformIntArray(const std::string& strUniform, const int* nVals, uint32_t unArySize);

		void UploadUniformFloat(const std::string& strUniform, float fValue);

	private:
		std::string ReadFile(const std::string& strFilePath);

		std::unordered_map<GLenum, std::string> PreProcess(const std::string& strShaderSrc);

#if 0
		void Compile(const std::unordered_map<GLenum, std::string>& mapShaderSrc);
#endif
		void CompileOrGetVulkanBinaries(const std::unordered_map<GLenum, std::string>& mapShaderSrc);

		void CompileOrGetOpenGLBinaries();

		void CreateProgram();

		void Reflect(GLenum stage, const std::vector<uint32_t>& vecShaderData);

	private:
		uint32_t m_unRendererID;		///< OpenGL shader id
		std::string m_strShaderName;	///< Shader name

		std::string m_strFilePath;		///< shader file path

		std::unordered_map<GLenum, std::vector<uint32_t>> m_mapVulkanSPIRV;	///< Vulkan glsl经由shaderc编译得到的spir_v文件(shaderc返回的值以4字节为一个单位)
		std::unordered_map<GLenum, std::vector<uint32_t>> m_mapOpenGLSPIRV;	///< OpenGL glsl经由shaderc编译得到的spir_v文件(shaderc返回的值以4字节为一个单位)

		std::unordered_map<GLenum, std::string> m_umapOpenGLSourceCode;	///< 不同着色器对应的源码字符串
	};
}